#include "gudb_server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <getopt.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdarg.h>

// Global server instance for signal handling
static gudb_server_t* g_server = NULL;

// Signal handler
void gudb_server_signal_handler(int sig) {
    if (g_server) {
        printf("\nReceived signal %d, shutting down server...\n", sig);
        g_server->running = false;
    }
}

// Server Lifecycle Functions

gudb_server_t* gudb_server_create(void) {
    gudb_server_t* server = malloc(sizeof(gudb_server_t));
    if (!server) return NULL;
    
    memset(server, 0, sizeof(gudb_server_t));
    
    // Initialize mutexes
    if (pthread_mutex_init(&server->session_mutex, NULL) != 0 ||
        pthread_mutex_init(&server->work_mutex, NULL) != 0 ||
        pthread_mutex_init(&server->stats_mutex, NULL) != 0 ||
        pthread_cond_init(&server->work_cond, NULL) != 0) {
        free(server);
        return NULL;
    }
    
    server->listen_sockfd = -1;
    server->next_session_id = 1;
    server->start_time = time(NULL);
    
    return server;
}

void gudb_server_destroy(gudb_server_t* server) {
    if (!server) return;
    
    // Stop server if running
    if (server->running) {
        gudb_native_server_stop(server);
    }
    
    // Close database
    if (server->database) {
        gudb_close(server->database);
    }
    
    // Clean up sessions
    gudb_session_t* session = server->sessions;
    while (session) {
        gudb_session_t* next = session->next;
        gudb_session_destroy(session);
        session = next;
    }
    
    // Clean up worker threads
    if (server->worker_threads) {
        free(server->worker_threads);
    }
    
    // Clean up mutexes
    pthread_mutex_destroy(&server->session_mutex);
    pthread_mutex_destroy(&server->work_mutex);
    pthread_mutex_destroy(&server->stats_mutex);
    pthread_cond_destroy(&server->work_cond);
    
    free(server);
}

int gudb_server_init(gudb_server_t* server, gudb_server_config_t* config) {
    if (!server || !config) return -1;
    
    // Copy configuration
    server->config = *config;
    
    // Open database
    server->database = gudb_open(config->data_dir, GU_OPEN_CREATE, 
                                config->username, config->password);
    if (!server->database) {
        gudb_server_log(server, "Failed to open database at %s", config->data_dir);
        return -1;
    }
    
    // Allocate worker threads
    server->worker_threads = malloc(config->worker_threads * sizeof(pthread_t));
    if (!server->worker_threads) {
        gudb_server_log(server, "Failed to allocate worker threads");
        return -1;
    }
    
    gudb_server_log(server, "GuDB server initialized successfully");
    gudb_server_log(server, "Database: %s", config->data_dir);
    gudb_server_log(server, "Listen address: %s:%d", config->host, config->port);
    gudb_server_log(server, "Max connections: %d", config->max_connections);
    gudb_server_log(server, "Worker threads: %d", config->worker_threads);
    
    return 0;
}

int gudb_native_server_start(gudb_server_t* server) {
    if (!server || server->running) return -1;
    
    // Create listen socket
    server->listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (server->listen_sockfd < 0) {
        gudb_server_log(server, "Failed to create socket: %s", strerror(errno));
        return -1;
    }
    
    // Set socket options
    int opt = 1;
    if (setsockopt(server->listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        gudb_server_log(server, "Failed to set socket options: %s", strerror(errno));
        close(server->listen_sockfd);
        return -1;
    }
    
    // Bind socket
    memset(&server->server_addr, 0, sizeof(server->server_addr));
    server->server_addr.sin_family = AF_INET;
    server->server_addr.sin_addr.s_addr = INADDR_ANY;
    server->server_addr.sin_port = htons(server->config.port);
    
    if (bind(server->listen_sockfd, (struct sockaddr*)&server->server_addr, 
             sizeof(server->server_addr)) < 0) {
        gudb_server_log(server, "Failed to bind socket: %s", strerror(errno));
        close(server->listen_sockfd);
        return -1;
    }
    
    // Start listening
    if (listen(server->listen_sockfd, 128) < 0) {
        gudb_server_log(server, "Failed to listen: %s", strerror(errno));
        close(server->listen_sockfd);
        return -1;
    }
    
    server->running = true;
    g_server = server;  // Set global reference for signal handler
    
    // Install signal handlers
    signal(SIGINT, gudb_server_signal_handler);
    signal(SIGTERM, gudb_server_signal_handler);
    
    // Start worker threads
    for (int i = 0; i < server->config.worker_threads; i++) {
        if (pthread_create(&server->worker_threads[i], NULL, 
                          gudb_server_worker_thread, server) != 0) {
            gudb_server_log(server, "Failed to create worker thread %d", i);
            server->running = false;
            return -1;
        }
    }
    
    // Start accept thread
    if (pthread_create(&server->accept_thread, NULL, 
                      gudb_server_accept_thread, server) != 0) {
        gudb_server_log(server, "Failed to create accept thread");
        server->running = false;
        return -1;
    }
    
    gudb_server_log(server, "GuDB server started successfully on port %d", server->config.port);
    return 0;
}

int gudb_native_server_stop(gudb_server_t* server) {
    if (!server || !server->running) return 0;
    
    gudb_server_log(server, "Stopping GuDB server...");
    server->running = false;
    
    // Wake up worker threads
    pthread_mutex_lock(&server->work_mutex);
    pthread_cond_broadcast(&server->work_cond);
    pthread_mutex_unlock(&server->work_mutex);
    
    // Wait for accept thread
    pthread_join(server->accept_thread, NULL);
    
    // Wait for worker threads
    for (int i = 0; i < server->config.worker_threads; i++) {
        pthread_join(server->worker_threads[i], NULL);
    }
    
    // Close listen socket
    if (server->listen_sockfd >= 0) {
        close(server->listen_sockfd);
        server->listen_sockfd = -1;
    }
    
    // Close all sessions
    pthread_mutex_lock(&server->session_mutex);
    gudb_session_t* session = server->sessions;
    while (session) {
        gudb_session_t* next = session->next;
        if (session->sockfd >= 0) {
            close(session->sockfd);
        }
        gudb_session_destroy(session);
        session = next;
    }
    server->sessions = NULL;
    server->session_count = 0;
    pthread_mutex_unlock(&server->session_mutex);
    
    gudb_server_log(server, "GuDB server stopped");
    return 0;
}

// Configuration Functions

void gudb_server_init_default_config(gudb_server_config_t* config) {
    if (!config) return;
    
    strcpy(config->host, "localhost");
    config->port = GU_DEFAULT_PORT;
    strcpy(config->data_dir, "/tmp/gudb_data");
    strcpy(config->username, "admin");
    strcpy(config->password, "admin");
    config->max_connections = 100;
    config->worker_threads = 4;
    config->daemon_mode = false;
    config->verbose = false;
}

int gudb_server_parse_args(gudb_server_config_t* config, int argc, char* argv[]) {
    if (!config) return -1;
    
    static struct option long_options[] = {
        {"host",        required_argument, 0, 'h'},
        {"port",        required_argument, 0, 'P'},
        {"data-dir",    required_argument, 0, 'd'},
        {"user",        required_argument, 0, 'u'},
        {"password",    required_argument, 0, 'p'},
        {"max-conn",    required_argument, 0, 'c'},
        {"threads",     required_argument, 0, 't'},
        {"daemon",      no_argument,       0, 'D'},
        {"verbose",     no_argument,       0, 'v'},
        {"help",        no_argument,       0, '?'},
        {0, 0, 0, 0}
    };
    
    int c;
    while ((c = getopt_long(argc, argv, "h:P:d:u:p:c:t:Dv?", long_options, NULL)) != -1) {
        switch (c) {
            case 'h':
                strncpy(config->host, optarg, sizeof(config->host) - 1);
                break;
            case 'P':
                config->port = atoi(optarg);
                break;
            case 'd':
                strncpy(config->data_dir, optarg, sizeof(config->data_dir) - 1);
                break;
            case 'u':
                strncpy(config->username, optarg, sizeof(config->username) - 1);
                break;
            case 'p':
                strncpy(config->password, optarg, sizeof(config->password) - 1);
                break;
            case 'c':
                config->max_connections = atoi(optarg);
                break;
            case 't':
                config->worker_threads = atoi(optarg);
                break;
            case 'D':
                config->daemon_mode = true;
                break;
            case 'v':
                config->verbose = true;
                break;
            case '?':
                gudb_server_print_usage(argv[0]);
                return 1;
            default:
                return -1;
        }
    }
    
    return 0;
}

void gudb_server_print_usage(const char* program_name) {
    printf("Usage: %s [OPTIONS]\n\n", program_name);
    printf("GuDB Server - Native GuDB database server\n\n");
    printf("Options:\n");
    printf("  -h, --host HOST          Bind to host (default: localhost)\n");
    printf("  -P, --port PORT          Listen port (default: %d)\n", GU_DEFAULT_PORT);
    printf("  -d, --data-dir DIR       Database directory (default: /tmp/gudb_data)\n");
    printf("  -u, --user USER          Admin username (default: admin)\n");
    printf("  -p, --password PASS      Admin password (default: admin)\n");
    printf("  -c, --max-conn NUM       Max connections (default: 100)\n");
    printf("  -t, --threads NUM        Worker threads (default: 4)\n");
    printf("  -D, --daemon             Run as daemon\n");
    printf("  -v, --verbose            Enable verbose logging\n");
    printf("  -?, --help               Show this help\n\n");
    printf("Examples:\n");
    printf("  %s                       # Start with defaults\n", program_name);
    printf("  %s -P 8888 -v            # Custom port with verbose logging\n", program_name);
    printf("  %s -d /data/gudb -D      # Custom data dir as daemon\n", program_name);
}

// Session Management

gudb_session_t* gudb_session_create(int sockfd, struct sockaddr_in* client_addr, uint32_t session_id) {
    gudb_session_t* session = malloc(sizeof(gudb_session_t));
    if (!session) return NULL;
    
    memset(session, 0, sizeof(gudb_session_t));
    session->sockfd = sockfd;
    session->client_addr = *client_addr;
    session->session_id = session_id;
    session->connect_time = time(NULL);
    session->last_activity = session->connect_time;
    
    return session;
}

void gudb_session_destroy(gudb_session_t* session) {
    if (!session) return;
    
    if (session->current_txn) {
        gudb_rollback(session->current_txn);
    }
    
    free(session);
}

int gudb_server_add_session(gudb_server_t* server, gudb_session_t* session) {
    if (!server || !session) return -1;
    
    pthread_mutex_lock(&server->session_mutex);
    
    if (server->session_count >= (uint32_t)server->config.max_connections) {
        pthread_mutex_unlock(&server->session_mutex);
        return -1;
    }
    
    // Add to linked list
    session->next = server->sessions;
    if (server->sessions) {
        server->sessions->prev = session;
    }
    server->sessions = session;
    server->session_count++;
    
    pthread_mutex_unlock(&server->session_mutex);
    return 0;
}

int gudb_server_remove_session(gudb_server_t* server, gudb_session_t* session) {
    if (!server || !session) return -1;
    
    pthread_mutex_lock(&server->session_mutex);
    
    // Remove from linked list
    if (session->next) {
        session->next->prev = session->prev;
    }
    if (session->prev) {
        session->prev->next = session->next;
    } else {
        server->sessions = session->next;
    }
    
    server->session_count--;
    
    pthread_mutex_unlock(&server->session_mutex);
    return 0;
}

// Protocol Handling

int gudb_server_handle_connect(gudb_server_t* server, gudb_session_t* session, gu_packet_t* packet) {
    if (!server || !session || !packet) return -1;
    
    // Parse connection data
    char* username = (char*)packet->payload;
    char* password = username + strlen(username) + 1;
    char* database = password + strlen(password) + 1;
    
    gudb_server_log(server, "Authentication attempt: user=%s, db=%s", username, database);
    
    // Authenticate
    if (gudb_server_authenticate(server, username, password) == 0) {
        session->authenticated = true;
        strncpy(session->username, username, sizeof(session->username) - 1);
        strncpy(session->database, database, sizeof(session->database) - 1);
        
        gudb_server_log(server, "User %s authenticated successfully", username);
        return gudb_server_send_auth_ok(session);
    } else {
        gudb_server_log(server, "Authentication failed for user %s", username);
        return gudb_server_send_auth_fail(session, "Invalid username or password");
    }
}

int gudb_server_handle_exec(gudb_server_t* server, gudb_session_t* session, gu_packet_t* packet) {
    if (!server || !session || !packet || !session->authenticated) return -1;
    
    char* sql = (char*)packet->payload;
    gudb_server_log(server, "Executing SQL: %s", sql);
    
    // Create or use existing transaction
    gudb_txn* txn = session->current_txn;
    bool created_txn = false;
    
    if (!txn) {
        gudb_server_log(server, "Creating transaction with database='%s' for SQL: %s", 
                       session->database, sql);
        txn = gudb_begin(server->database, GU_TXN_RC, session->database);
        if (!txn) {
            return gudb_server_send_error(session, "Failed to create transaction");
        }
        // Copy session's database selection state to transaction
        txn->database_explicitly_selected = session->database_explicitly_selected;
        created_txn = true;
        session->current_txn = txn;
    }
    
    // Execute SQL
    result_t* result = NULL;
    int exec_result = gudb_exec(txn, sql, NULL, &result);
    
    // Check if it was a successful USE command and update session database
    if (exec_result == GU_OK && strncasecmp(sql, "use ", 4) == 0) {
        const char* current_db = gudb_txn_current_database(txn);
        gudb_server_log(server, "USE command: txn database='%s', session database='%s'", 
                       current_db ? current_db : "NULL", session->database);
        if (current_db && strcmp(session->database, current_db) != 0) {
            strncpy(session->database, current_db, sizeof(session->database) - 1);
            session->database[sizeof(session->database) - 1] = '\0';
            gudb_server_log(server, "Updated session database to '%s'", session->database);
        }
        // Mark that user has explicitly selected a database
        session->database_explicitly_selected = true;
    }
    
    if (exec_result != GU_OK) {
        if (created_txn) {
            gudb_rollback(txn);
            session->current_txn = NULL;
        }
        
        const char* error_msg = "SQL execution failed";
        switch (exec_result) {
            case GU_ERR_SYNTAX: error_msg = "Syntax error"; break;
            case GU_ERR_NOMEM:  error_msg = "Out of memory"; break;
            case GU_ERR_IO:     error_msg = "I/O error"; break;
            default:            error_msg = "Unknown error"; break;
        }
        
        return gudb_server_send_error(session, error_msg);
    }
    
    // Send result
    int ret = gudb_server_send_result(session, result);
    
    if (result) {
        gudb_free_result(result);
    }
    
    // Auto-commit
    if (created_txn) {
        gudb_commit(txn);
        session->current_txn = NULL;
    }
    
    session->queries_executed++;
    session->last_activity = time(NULL);
    
    return ret;
}

int gudb_server_handle_query(gudb_server_t* server, gudb_session_t* session, gu_packet_t* packet) {
    // For now, query and exec are handled the same way
    return gudb_server_handle_exec(server, session, packet);
}

int gudb_server_handle_ping(gudb_server_t* server, gudb_session_t* session, gu_packet_t* packet) {
    (void)server;  // Suppress unused parameter warning
    (void)packet;  // Suppress unused parameter warning
    return gudb_server_send_pong(session);
}

int gudb_server_handle_quit(gudb_server_t* server, gudb_session_t* session, gu_packet_t* packet) {
    (void)packet;  // Suppress unused parameter warning
    gudb_server_log(server, "Client %s disconnecting", gudb_session_get_client_ip(session));
    return -1;  // Signal to close connection
}

// Response Helpers

int gudb_server_send_auth_ok(gudb_session_t* session) {
    gu_packet_t* response = gu_packet_create(GU_RESP_AUTH_OK, 0);
    if (!response) return -1;
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

int gudb_server_send_auth_fail(gudb_session_t* session, const char* message) {
    size_t msg_len = message ? strlen(message) + 1 : 1;
    gu_packet_t* response = gu_packet_create(GU_RESP_AUTH_FAIL, msg_len);
    if (!response) return -1;
    
    if (message) {
        strcpy((char*)response->payload, message);
    } else {
        response->payload[0] = '\0';
    }
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

int gudb_server_send_ok(gudb_session_t* session, const char* message) {
    size_t msg_len = message ? strlen(message) + 1 : 1;
    gu_packet_t* response = gu_packet_create(GU_RESP_OK, msg_len);
    if (!response) return -1;
    
    if (message) {
        strcpy((char*)response->payload, message);
    } else {
        response->payload[0] = '\0';
    }
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

int gudb_server_send_error(gudb_session_t* session, const char* message) {
    size_t msg_len = message ? strlen(message) + 1 : 1;
    gu_packet_t* response = gu_packet_create(GU_RESP_ERROR, msg_len);
    if (!response) return -1;
    
    if (message) {
        strcpy((char*)response->payload, message);
    } else {
        response->payload[0] = '\0';
    }
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

int gudb_server_send_result(gudb_session_t* session, result_t* gudb_result) {
    char result_text[8192] = {0};
    int offset = 0;
    
    // printf("DEBUG: gudb_server_send_result - result=%p\n", (void*)gudb_result);
    // if (gudb_result) {
    //     printf("DEBUG: col_count=%u, row_count=%u\n", gudb_result->col_count, gudb_result->row_count);
    // }
    
    if (gudb_result && gudb_result->col_count > 0 && gudb_result->row_count > 0) {
        // printf("DEBUG: Condition met - formatting table\n");
        // Format as a proper table with column headers and rows
        
        // Calculate column widths for proper alignment
        int* col_widths = calloc(gudb_result->col_count, sizeof(int));
        if (!col_widths) return -1;
        
        // Calculate maximum width for each column
        for (uint32_t i = 0; i < gudb_result->col_count; i++) {
            col_widths[i] = strlen(gudb_result->column_names[i]);
        }
        
        for (uint32_t row = 0; row < gudb_result->row_count; row++) {
            for (uint32_t col = 0; col < gudb_result->col_count; col++) {
                if (gudb_result->rows[row][col]) {
                    int len = strlen(gudb_result->rows[row][col]);
                    if (len > col_widths[col]) {
                        col_widths[col] = len;
                    }
                }
            }
        }
        
        // Build table header separator line
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        for (uint32_t i = 0; i < gudb_result->col_count; i++) {
            for (int j = 0; j < col_widths[i] + 2; j++) {
                offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "-");
            }
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        }
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "\n");
        
        // Build column headers
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "|");
        for (uint32_t i = 0; i < gudb_result->col_count; i++) {
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, " %-*s |", 
                             col_widths[i], gudb_result->column_names[i]);
        }
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "\n");
        
        // Build separator line again
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        for (uint32_t i = 0; i < gudb_result->col_count; i++) {
            for (int j = 0; j < col_widths[i] + 2; j++) {
                offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "-");
            }
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        }
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "\n");
        
        // Build data rows
        for (uint32_t row = 0; row < gudb_result->row_count; row++) {
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "|");
            for (uint32_t col = 0; col < gudb_result->col_count; col++) {
                const char* cell_value = gudb_result->rows[row][col] ? gudb_result->rows[row][col] : "NULL";
                offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, " %-*s |", 
                                 col_widths[col], cell_value);
            }
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "\n");
        }
        
        // Build bottom border
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        for (uint32_t i = 0; i < gudb_result->col_count; i++) {
            for (int j = 0; j < col_widths[i] + 2; j++) {
                offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "-");
            }
            offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "+");
        }
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, "\n");
        
        // Add row count summary
        offset += snprintf(result_text + offset, sizeof(result_text) - offset - 1, 
                          "%u rows in set\n", gudb_result->row_count);
        
        free(col_widths);
    } else {
        // printf("DEBUG: Condition not met - using fallback message\n");
        strcpy(result_text, "Query executed successfully.\n");
    }
    
    // printf("DEBUG: Final result_text length=%zu, content:\n%s\n", strlen(result_text), result_text);
    
    gu_packet_t* response = gu_packet_create(GU_RESP_RESULT, strlen(result_text) + 1);
    if (!response) return -1;
    
    strcpy((char*)response->payload, result_text);
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

int gudb_server_send_pong(gudb_session_t* session) {
    gu_packet_t* response = gu_packet_create(GU_RESP_PONG, 0);
    if (!response) return -1;
    
    int ret = gu_packet_send(session->sockfd, response);
    gu_packet_destroy(response);
    return ret;
}

// Threading

void* gudb_server_accept_thread(void* arg) {
    gudb_server_t* server = (gudb_server_t*)arg;
    if (!server) return NULL;
    
    while (server->running) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        
        int client_sockfd = accept(server->listen_sockfd, 
                                  (struct sockaddr*)&client_addr, 
                                  &client_addr_len);
        
        if (client_sockfd < 0) {
            if (errno == EINTR && !server->running) break;
            continue;
        }
        
        // Create session
        gudb_session_t* session = gudb_session_create(client_sockfd, &client_addr, 
                                                     server->next_session_id++);
        if (!session) {
            close(client_sockfd);
            continue;
        }
        
        // Add to server
        if (gudb_server_add_session(server, session) < 0) {
            gudb_session_destroy(session);
            close(client_sockfd);
            continue;
        }
        
        // Create handler thread
        pthread_t handler_thread;
        if (pthread_create(&handler_thread, NULL, gudb_session_handler, session) == 0) {
            pthread_detach(handler_thread);
            
            pthread_mutex_lock(&server->stats_mutex);
            server->total_connections++;
            server->current_connections++;
            pthread_mutex_unlock(&server->stats_mutex);
            
            gudb_server_log(server, "New client connected from %s (session %u)", 
                           gudb_session_get_client_ip(session), session->session_id);
        } else {
            gudb_server_remove_session(server, session);
            gudb_session_destroy(session);
            close(client_sockfd);
        }
    }
    
    return NULL;
}

void* gudb_server_worker_thread(void* arg) {
    gudb_server_t* server = (gudb_server_t*)arg;
    
    while (server->running) {
        pthread_mutex_lock(&server->work_mutex);
        pthread_cond_wait(&server->work_cond, &server->work_mutex);
        pthread_mutex_unlock(&server->work_mutex);
        
        if (!server->running) break;
        
        // Worker thread logic would go here for more complex scenarios
    }
    
    return NULL;
}

void* gudb_session_handler(void* arg) {
    gudb_session_t* session = (gudb_session_t*)arg;
    if (!session) return NULL;
    
    gudb_server_t* server = g_server;  // Use global server reference
    
    while (server->running) {
        gu_packet_t* packet = gu_packet_recv(session->sockfd);
        if (!packet) break;
        
        int result = 0;
        
        switch (packet->header.command) {
            case GU_CMD_CONNECT:
                result = gudb_server_handle_connect(server, session, packet);
                break;
            case GU_CMD_EXEC:
                result = gudb_server_handle_exec(server, session, packet);
                break;
            case GU_CMD_QUERY:
                result = gudb_server_handle_query(server, session, packet);
                break;
            case GU_CMD_PING:
                result = gudb_server_handle_ping(server, session, packet);
                break;
            case GU_CMD_QUIT:
                result = gudb_server_handle_quit(server, session, packet);
                break;
            default:
                gudb_server_send_error(session, "Unknown command");
                result = -1;
                break;
        }
        
        gu_packet_destroy(packet);
        
        if (result < 0) break;
    }
    
    // Cleanup
    gudb_server_log(server, "Client %s disconnected (session %u)", 
                   gudb_session_get_client_ip(session), session->session_id);
    
    if (session->sockfd >= 0) {
        close(session->sockfd);
    }
    
    gudb_server_remove_session(server, session);
    
    pthread_mutex_lock(&server->stats_mutex);
    server->current_connections--;
    pthread_mutex_unlock(&server->stats_mutex);
    
    gudb_session_destroy(session);
    
    return NULL;
}

// Utilities

void gudb_server_print_stats(gudb_server_t* server) {
    if (!server) return;
    
    pthread_mutex_lock(&server->stats_mutex);
    
    time_t uptime = time(NULL) - server->start_time;
    
    printf("GuDB Server Statistics:\n");
    printf("  Uptime: %ld seconds\n", uptime);
    printf("  Listen address: %s:%d\n", server->config.host, server->config.port);
    printf("  Total connections: %llu\n", server->total_connections);
    printf("  Current connections: %llu\n", server->current_connections);
    printf("  Total queries: %llu\n", server->total_queries);
    printf("  Worker threads: %d\n", server->config.worker_threads);
    printf("  Max connections: %d\n", server->config.max_connections);
    
    pthread_mutex_unlock(&server->stats_mutex);
}

void gudb_server_log(gudb_server_t* server, const char* format, ...) {
    if (!server || (!server->config.verbose && server->config.daemon_mode)) return;
    
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    char timestamp[64];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info);
    
    printf("[%s] GuDB: ", timestamp);
    
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    
    printf("\n");
    fflush(stdout);
}

const char* gudb_session_get_client_ip(gudb_session_t* session) {
    if (!session) return "unknown";
    return inet_ntoa(session->client_addr.sin_addr);
}

// Authentication

int gudb_server_authenticate(gudb_server_t* server, const char* username, const char* password) {
    if (!server || !username || !password) return -1;
    
    // Simple authentication - in production, this would be more sophisticated
    if (strcmp(username, server->config.username) == 0 && 
        strcmp(password, server->config.password) == 0) {
        return 0;
    }
    
    return -1;
}